package com.renu.jdependencyanalyser.core;

import com.renu.jdependencyanalyser.cons.ProjectCons;
import com.renu.jdependencyanalyser.model.*;
import soot.*;

import java.util.*;

public class ProjectInfo {
    // 客户类
    private Map<String, ClassModel> classModelMap = new HashMap<>();

    private Map<String , MethodModel> methodModelMap = new HashMap<>();

    @Deprecated
    private Map<String, FieldModel> fieldModelMap = new HashMap<>();

    private Map<String , JarModel> jarModelMap = new HashMap<>();

    private Map<String, PackageModel> packageModelMap = new HashMap<>();


    private Map<String,PackageModel> outerPckMap = new HashMap<>();

    private Map<String,ClassModel> outerClassMap = new HashMap<>();



    private Map<String,JarModel> borderJarMap = new HashMap<>();


    private Map<String,MethodModel> borderMethodMap = new HashMap<>();


    private Map<String,ClassModel> borderClassMap = new HashMap<>();

    @Deprecated
    private Set<String> borderMethods= new HashSet<>();

    public Map<String, JarModel> getBorderJarMap() {
        return borderJarMap;
    }

    public Map<String, ClassModel> getBorderClassMap() {
        return borderClassMap;
    }

    public void addBorderClass(String clsSig) {
        if (clsSig == null)
            return;
        ClassModel model = outerClassMap.get(clsSig);
        if (model == null)
            return;

        borderClassMap.put(clsSig,model);
    }



    public Map<String, PackageModel> getOuterPckMap() {
        return outerPckMap;
    }

    public Map<String, MethodModel> getMethodModelMap() {
        return methodModelMap;
    }

    public MethodModel getOuterMethod(String methodSig){
        return borderMethodMap.get(methodSig);
    }

    public Map<String, MethodModel> getBorderMethodMap() {
        return borderMethodMap;
    }

    public Map<String, ClassModel> getOuterClassMap() {
        return outerClassMap;
    }

    public MethodModel getMethod(String methodSig) {
        return this.methodModelMap.get(methodSig);
    }

    public void pckBindJar(String pckSig, String jarSig) {
        PackageModel packageModel = packageModelMap.get(pckSig);
        JarModel jarModel = jarModelMap.get(jarSig);
        if (packageModel!= null && jarModel!= null){
            packageModel.setJarSig(jarSig);
            jarModel.addPck(pckSig);
        }


    }

    public void classBindPck(String className, String pckSig) {
        ClassModel classModel = classModelMap.get(className);
        PackageModel packageModel = packageModelMap.get(pckSig);
        if (classModel!= null && packageModel != null){
            classModel.setPck(pckSig);
            packageModel.addClass(className);
        }


    }

    public void outerClassBindPck(String className, String pckSig) {
        ClassModel classModel = outerClassMap.get(className);
        PackageModel packageModel = outerPckMap.get(pckSig);
        if (classModel!= null && packageModel != null){
            classModel.setPck(pckSig);
            packageModel.addClass(className);
        }


    }
    public void addPck(PackageModel packageModel) {
        String pckSig = packageModel.getPckSig();
        if (packageModelMap.containsKey(pckSig)) {
            return ;
        }
        packageModelMap.put(pckSig,packageModel);
    }

    public void addOuterPck(PackageModel packageModel) {
        String pckSig = packageModel.getPckSig();
        if (outerPckMap.containsKey(pckSig)) {
            return ;
        }
        outerPckMap.put(pckSig,packageModel);
    }

    /**
     * classname ，fatherclass
     * @param sootClass
     */

    public void setOrAddClass(SootClass sootClass) {

        String className= sootClass.getName();
        ClassModel classModel = null;
        if (classModelMap.containsKey(className)){
            classModel = getClassModel(className);
        }else{
           classModel =  new ClassModel(className);
        }

        if (sootClass.hasSuperclass()){
            String fatherClassName = sootClass.getSuperclass().getName();
            if(!"java.lang.Object".equals(fatherClassName)){
                classModel.setExtendClsSig(fatherClassName);
            }
        }
        this.classModelMap.put(className,classModel);

    }

    public void addClass(SootClass sootClass) {

        String className= sootClass.getName();
        if (classModelMap.containsKey(className)){
            return ;
        }
        ClassModel classModel = new ClassModel(className);

        if (sootClass.hasSuperclass()){
            String fatherClassName = sootClass.getSuperclass().getName();
            if(!"java.lang.Object".equals(fatherClassName)){
                classModel.setExtendClsSig(fatherClassName);
            }
        }
        this.classModelMap.put(className,classModel);

    }

    @Deprecated
    public void addMethod(SootMethod method) {
        String methodSig = method.getSignature();
        if (methodModelMap.containsKey(methodSig)){
            return ;
        }
        MethodModel methodModel = new MethodModel(methodSig);

        methodModelMap.put(methodSig,methodModel);
        
    }

    public void addMethod(MethodModel method) {
        String methodSig = method.getMethodSig();
        if (methodModelMap.containsKey(methodSig)){
            return ;
        }
        methodModelMap.put(methodSig,method);

    }
    public void methodBindClass(String methodSig, String className) {
       if (methodModelMap.containsKey(methodSig) && classModelMap.containsKey(className)){

           ClassModel classModel = classModelMap.get(className);
           MethodModel methodModel = methodModelMap.get(methodSig);
           classModel.addMethod(methodSig);
           methodModel.setClassSig(className);

       }


    }

    @Deprecated
    public void addField(SootField field) {
        String fieldSig = field.getSignature();
        if (fieldModelMap.containsKey(fieldSig)) {
            return;
        }
        FieldModel fieldModel = new FieldModel(fieldSig);
        fieldModelMap.put(fieldSig,fieldModel);


    }

    public  void addField(String fieldSig){
        if (fieldModelMap.containsKey(fieldSig)) {
            return;
        }
        FieldModel fieldModel = new FieldModel(fieldSig);
        fieldModelMap.put(fieldSig,fieldModel);

    }

    public void fieldBindClass(String fieldSig, String className) {
        FieldModel fieldModel = fieldModelMap.get(fieldSig);
        ClassModel classModel = classModelMap.get(className);
        if (fieldModel!= null && classModel!= null){
            classModel.addField(fieldSig);
            fieldModel.setClassName(className);
        }

    }

    public void fieldBindType(String fieldSig, String type) {
        FieldModel fieldModel = fieldModelMap.get(fieldSig);
        if (fieldModel!= null){
            fieldModel.setType(type);
        }
    }

    public void methodBindLocals(String methodSig, String localType) {
        MethodModel methodModel = methodModelMap.get(methodSig);
        if (methodModel!= null){
            methodModel.addLocal(localType);
        }

    }

    public void addJar(JarModel jarModel) {
        String jarSig = jarModel.getJarSig();
        if (jarModelMap.containsKey(jarSig)){
            return ;
        }

        jarModelMap.put(jarSig,jarModel);
    }

    public void addOuterJar(JarModel jarModel) {
        String jarSig = jarModel.getJarSig();
        if (jarModelMap.containsKey(jarSig)){
            return ;
        }

        jarModelMap.put(jarSig,jarModel);
    }


    public void addAllJar(HashSet<JarModel> jars) {
        for (JarModel jar : jars) {
            if (this.jarModelMap.containsKey(jar.getJarSig())){
                continue;
            }
            this.jarModelMap.put(jar.getJarSig(),jar);
        }
    }


    public void packageBindJar(String jarSig, String pckSig) {
        JarModel jarModel = this.jarModelMap.get(jarSig);
        PackageModel packageModel = this.packageModelMap.get(pckSig);
        if (jarModel!= null && packageModel!= null){
            jarModel.addPck(pckSig);
            packageModel.setJarSig(jarSig);
        }


    }

    public ClassModel getClassModel(String className) {
        return this.classModelMap.get(className);
    }


    public void addClass(ClassModel classModel) {
        String clsSig = classModel.getClsSig();
        if (this.classModelMap.containsKey(clsSig)){
            return;
        }
        this.classModelMap.put(clsSig,classModel);

    }
    public void addOuterClass(ClassModel classModel) {
        String clsSig = classModel.getClsSig();
        if (this.outerClassMap.containsKey(clsSig)){
            return;
        }
        this.outerClassMap.put(clsSig,classModel);

    }

    public void outerPackageBindJar(String jarSig, String pckSig) {
        JarModel jarModel = this.borderJarMap.get(jarSig);
        PackageModel packageModel = this.outerPckMap.get(pckSig);
        if (jarModel!= null && packageModel!= null){
            jarModel.addPck(pckSig);
            packageModel.setJarSig(jarSig);
        }


    }
    public void addBorderMethod(String borderMethodSig) {
        MethodModel methodModel = this.methodModelMap.get(borderMethodSig);
        if (methodModel!= null){
            String classSig = methodModel.getClassSig();
            String pck = this.classModelMap.get(classSig).getPck();
            String jarSig = packageModelMap.get(pck).getJarSig();
            if (!ProjectCons.PROJECT_SELF_NAME.equals(jarSig)){
                this.borderMethods.add(borderMethodSig);
            }

        }

    }
    @Deprecated
    public boolean bindInOut(String srcSig , String  tgtSig) {

            MethodModel srcMethodModel = this.getMethod(srcSig);
            MethodModel tgtMethodModel = this.getMethod(tgtSig);
            if (srcMethodModel!= null && tgtMethodModel!=null){
                srcMethodModel.addOuterMethod(tgtMethodModel.getMethodSig());
                tgtMethodModel.addInnerMethod(srcMethodModel.getMethodSig());
                return true;
            }

        return  false;
    }

    public boolean bindInOut(MethodModel srcMethodModel , MethodModel  tgtMethodModel) {


        if (srcMethodModel!= null && tgtMethodModel!=null){
            srcMethodModel.addOuterMethod(tgtMethodModel.getMethodSig());
            tgtMethodModel.addInnerMethod(srcMethodModel.getMethodSig());
            return true;
        }

        return  false;
    }


    public void addBorderMethod(MethodModel borderMethod) {
        String methodSig = borderMethod.getMethodSig();
        if (!this.borderMethodMap.containsKey(methodSig)){
            this.borderMethodMap.put(methodSig,borderMethod);
        }

    }

    public MethodModel getBorderMethod(String methodSig) {
        return  this.borderMethodMap.get(methodSig);
    }


    public void bindSrcTgtCls(ClassModel srcClass, ClassModel tgtClass) {
        if (srcClass == null || tgtClass ==null){
            return;
        }
        srcClass.getTgtClsSig().add(tgtClass.getClsSig());
        tgtClass.getSrcClsSig().add(srcClass.getClsSig());
    }

    public Map<String, JarModel> getJarModelMap() {
        return jarModelMap;
    }
}
